# 图像扫描逻辑
import cv2
import numpy as np
from transform import four_point_transform
from skimage.filters import threshold_local
import imutils
import io


def scan_image(image_data):
    # 将二进制数据转换为 OpenCV 图像
    nparr = np.frombuffer(image_data, np.uint8)
    image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)

    # 调整图像大小
    # 当你预缩放图像（image = imutils.resize(image, height=500)）时：
    #
    # 轮廓检测在缩小的图像上进行
    # 检测到的角点坐标是缩小图像上的坐标
    # 但是透视变换是在原始尺寸图像上进行的
    # 所以需要 * ratio 来将缩小图像上的坐标转换回原始图像的坐标
    # 现在你的修改导致的问题：
    # 当你不预缩放图像时：
    #
    # 轮廓检测在原始尺寸图像上进行
    # 检测到的角点坐标是原始图像上的坐标
    # 透视变换也在原始尺寸图像上进行
    # 但是你删除了 * ratio，这导致了坐标不匹配
    ratio = image.shape[0] / 500.0
    orig = image.copy()
    image = imutils.resize(image, height=500)

    # 边缘检测
    # 修改：在原始尺寸图像上进行边缘检测
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray = cv2.GaussianBlur(gray, (5, 5), 0)
    # edged = cv2.Canny(gray, 75, 200)
    edged = cv2.Canny(gray, 30, 150)  # 降低阈值，检测更多边缘


    # 寻找轮廓
    cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    cnts = sorted(cnts, key=cv2.contourArea, reverse=True)[:5]

    screenCnt = None
    for c in cnts:
        peri = cv2.arcLength(c, True)
        approx = cv2.approxPolyDP(c, 0.02 * peri, True)
        if len(approx) == 4:
            screenCnt = approx
            break

    #如果没有找到四边形轮廓，返回原图
    if screenCnt is None:
        warped = orig
    else:
        # 应用透视变换
        # 修改：不需要比例转换，因为没有预缩放
        warped = four_point_transform(orig, screenCnt.reshape(4, 2) * ratio)

    # 转换为灰度图并进行阈值处理
    warped = cv2.cvtColor(warped, cv2.COLOR_BGR2GRAY)
    T = threshold_local(warped, 1, offset=10, method="gaussian")
    warped = (warped > T).astype("uint8") * 255

    # 使用OpenCV的resize函数，可以控制插值方法
    height, width = warped.shape
    new_height = 500
    new_width = int(width * new_height / height)
    final_image = cv2.resize(warped, (new_width, new_height), interpolation=cv2.INTER_CUBIC)

    _, encoded = cv2.imencode('.jpg', final_image)
    return encoded.tobytes()